package com.mytinyRPC.framework.loadBalance.Impl;



import com.mytinyRPC.framework.URL;

import java.util.*;

//一致性hash算法
public class ConsistentHash {
    private static Map<String,SortedMap<Integer, String>> virtualNodes = new HashMap<>();
    private static final int VIRTUAL_NODES = 160;
    public static void refresh(Map<String, List<URL>> registerMap){
        // 对每个真实节点添加虚拟节点，虚拟节点会根据哈希算法进行散列
        for (String str:registerMap.keySet()){
            for (URL ip : registerMap.get(str)) {
                for (int i = 0; i < VIRTUAL_NODES; i++) {
                    int hash = getHash(ip.getHostname()+ip.getPort()+"VN"+i);
                    virtualNodes.get(str).put(hash, ip.getHostname()+ip.getPort());
                }
            }
        }

    }

    public static String getServer(String interfaceName,String client) {
        int hash = getHash(client);
        // 得到大于该Hash值的排好序的Map
        SortedMap<Integer, String> subMap = virtualNodes.get(interfaceName).tailMap(hash);
        // 大于该hash值的第一个元素的位置
        Integer nodeIndex = subMap.firstKey();
        // 如果不存在大于该hash值的元素，则返回根节点
        if (nodeIndex == null) {
            nodeIndex = virtualNodes.get(interfaceName).firstKey();
        }
        // 返回对应的虚拟节点名称
        return subMap.get(nodeIndex);
    }
    public static int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++)
            hash = (hash ^ str.charAt(i)) * p;
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        // 如果算出来的值为负数则取其绝对值
        if (hash < 0)
            hash = Math.abs(hash);
        return hash;
    }

    /*public static void main(String[] args) {
        // 连续调用10次,随机10个client
        for (int i = 0; i < 10; i++) {
            System.out.println(getServer("client" + i));
        }
    }*/
}
